﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Data.Entity.Validation;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Net;
using System.Net.Mail;
using System.Security.Cryptography;
using System.Text;
using EF5;


namespace DataContextLayer
{
    public class DatabaseHelper
    {
        public DclContext Context { get; protected set; }

        public BackgroundWorker RunTasks { get; protected set; }

        public string Messages { get; protected set; }
        protected int _userId;
        public string UserName { get; protected set; }
        public string UserPassword { get; protected set; }
        public string UserEmail { get; protected set; }

        public int ResetId { get; protected set; }

        public bool UserAccountLocked = false;
        public bool UserPasswordReset = false;

        protected enum LoginStatus
        {
            Pass,
            Fail,
            Locked,
            Reset
        }

        protected LoginStatus Status;


        public DatabaseHelper()
        {
            RunTasks = new BackgroundWorker();
            RunTasks.DoWork += RunTasksDoWork;
            RunTasks.RunWorkerCompleted += RunTasksRunWorkerCompleted;
            RunTasks.WorkerReportsProgress = true;
            
        }

        public virtual void RunTasksRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            
        }

        protected void RunTasksDoWork(object sender, DoWorkEventArgs e)
        {
            
            SendUserPasswordReset();
        }

        public DatabaseHelper(Dictionary<string, string> userName)
        {
            GetUserValues(userName);
        }

        public void GetUserValues(Dictionary<string, string> userName)
        {
            foreach (var valuePair in userName)
            {
                switch (valuePair.Key)
                {
                    case "txtUserName":
                        UserName = valuePair.Value;
                        break;
                    case "txtUserPassword":
                        UserPassword = valuePair.Value;
                        break;
                    case "txtUserEmail":
                        UserEmail = valuePair.Value;
                        break;
                }
            }
        }


        public virtual string GetMessage()
        {
            return Messages;
        }

        protected bool CheckPasswordLength()
        {
            if (UserPassword.Length < 6)
            {
                Messages = "Password needs to be atleast 6 charecters";
                return false;
            }
            return true;
        }

        protected IQueryable<User> FindUserByEmailOrName(DclContext context)
        {
            var user = from u in context.Users
                       where u.UserName.Equals(UserName) ||
                             u.UserEmail.Equals(UserEmail)
                       select u;
            return user;
        }
        
        public bool SendUserPasswordReset()
        {

            using (Context = new DclContext())
            {
                var userId = Context.Users.Where(u => u.UserName.Equals(UserName));

                var eMail = Context.Users.Find(userId.Select(u => u.UserId).First());

                string newPassword = GetRandomString();

                string tempPassword = newPassword;

                newPassword = GetSha1Hash(newPassword);

                Context.Entry(eMail).Property(u => u.UserPassword).CurrentValue = newPassword;

                Context.Entry(eMail).Property(u => u.UserPasswordReset).CurrentValue = true;

                Context.Entry(eMail).Property(u => u.UserAcountLocked).CurrentValue = true;

                Context.Entry(eMail).Property(u => u.FailedLoginAttempts).CurrentValue = 0;

                var userEmailAddress = userId.Select(u => u.UserEmail).First();

                SendEMailThroughGmail(userEmailAddress, tempPassword);

                UserPasswordReset = true;

                return SaveToDb(Context);
            }   
        }

        protected ParallelQuery<User> FindUserByEmail(DclContext context)
        {
            using (context)
            {
                var user = context.Users.Where(u => u.UserEmail.Equals(UserEmail)).AsParallel();

                return user;
            }
        }

        public bool ResetPassword()
        {
            using (Context = new DclContext())
            {

                var tempPass = GetSha1Hash(UserPassword);

                var resetUserPass = Context.Users.Find(ResetId);

                Context.Entry(resetUserPass).Property(u => u.UserPassword).CurrentValue = tempPass;

                Context.Entry(resetUserPass).Property(u => u.UserPasswordReset).CurrentValue = false;

                Context.Entry(resetUserPass).Property(u => u.UserAcountLocked).CurrentValue = false;

                return SaveToDb(Context); 
                
            }
        }

        protected bool InsertUser(DclContext context)
        {
            var newUser = new User
            {
                UserName = UserName,
                UserPassword = GetSha1Hash(UserPassword),
                UserEmail = UserEmail,
                UserPasswordReset = false
            };

            context.Users.Add(newUser);


            return SaveToDb(context);
        }


        protected bool SaveToDb(DclContext context)
        {

            try
            {
                context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (var ve in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in ve.ValidationErrors)
                    {
                        Messages += string.Format("Property: {0} Error: Invalid Entry \n", validationError.PropertyName);
                    }
                }

                return false;
            }
            return true;
        }


        protected string GetSha1Hash(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                return null;
            }

            var sha1 = new SHA1Managed();
            var bytes = sha1.ComputeHash(new UnicodeEncoding().GetBytes(data));

            return Convert.ToBase64String(bytes);
        }

        protected string GetRandomString()
        {

            var path = Path.GetRandomFileName();

            path = path.Replace(".", "");

            return path;

        }

        public bool IsNotEmpty<T>(IEnumerable<T> data)
        {

            return data != null && data.Any();

        }


        public static void InitDB()
        {
            using (var context = new DclContext())
            {
                var user = context.Users.Count();
            }

        }

        public void SendEMailThroughGmail(string uEmail, string newPassword)
        {

            try
            {

                using (var mailMessage = new MailMessage())
                {

                    mailMessage.From = new MailAddress("blue.harvest.team@gmail.com");

                    mailMessage.To.Add(uEmail);

                    mailMessage.Subject = "Your new password";

                    mailMessage.Body = "Your password has been reset to : " + newPassword + " :\n you will be asked to Reset your password on login";

                    mailMessage.IsBodyHtml = true;

                    using (var smtpClient = new SmtpClient("smtp.gmail.com"))
                    {
                        smtpClient.Port = 587;

                        smtpClient.Credentials = new NetworkCredential("blue.harvest.team@gmail.com", "SeniorProject");

                        smtpClient.EnableSsl = true;

                        smtpClient.Send(mailMessage);
                    }
                }
            }
            catch (Exception ex)
            {

                Messages += ex;

            }
        }
        
    }
}

